/*******************************************************************************
 * Copyright 2007 Vidar Svansson
 *     
 * This file is part of JAdapter.
 * 
 * JAdapter is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * JAdapter is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with JAdapter.  If not, see <http://www.gnu.org/licenses/>.
 *******************************************************************************/


package org.jadapter.tests;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;

import org.jadapter.Adapter;
import org.jadapter.JAdapter;
import org.jadapter.adapters.MapList;
import org.jadapter.func.Lambda;
import org.jadapter.tests.examples.CommaSeparated;
import org.jadapter.tests.examples.CommaSeparatedAdapter;
import org.jadapter.tests.examples.CommaSeparatedFactory;
import org.jadapter.tests.examples.CommaSeparatedFactoryMethod;
import org.jadapter.tests.examples.CommaSeparatedList;
import org.jadapter.tests.examples.CommaSeparatedListAdapter;
import org.jadapter.tests.examples.CommaSeparatedMap;
import org.jadapter.tests.examples.CommaSeparatedSetter;
import org.jadapter.tests.examples.CommaSeparatedStaticFactory;

@SuppressWarnings("unchecked")
public class TestAdapters extends BaseTestCase {


    /* Test adapters that implement Adapter */
    public void testSelfAdapter() throws Exception {
        // This wrapping is not really needed since
        // CommaSeparatedListAdapter is an Adapter
        JAdapter<CommaSeparated,List<?>> adapter = 
            new JAdapter<CommaSeparated,List<?>>
                (new CommaSeparatedListAdapter()); 

        assertTrue(adapter.isFactory());
        
        commas = adapter.adapt(list);
        String listCs = commas.getCommaSeparated();
        assertEquals("comma separated list", "Foo,Bar", listCs);
        assertTrue(adapter.isFactory());

        
        // So we can also just skip the use of JAdapter
        Adapter<CommaSeparated,List<?>> adapter1 = new CommaSeparatedListAdapter();
        commas = adapter1.adapt(list);
        listCs = commas.getCommaSeparated();
        assertEquals("comma separated list", "Foo,Bar", listCs);		
    }


    public void testSetterAdapter() throws Exception {
        assertFalse(listAdapter.isFactory());
        commas = listAdapter.adapt(list);
        assertTrue(listAdapter.isFactory());

        String listCs = commas.getCommaSeparated();
        assertEquals("comma separated list", "Foo,Bar", listCs);
    }


    public void testConstructorAdapter() throws Exception {
        assertFalse(mapAdapter.isFactory());

        commas = mapAdapter.adapt(map);
        assertTrue(mapAdapter.isFactory());

        String listCs = commas.getCommaSeparated();
        assertEquals("comma separated map", "Foo:foo,Bar:bar", listCs);
    }	

/*    public void testCheckedFactoryAdapter() throws Exception {
        assertFalse(commaSeparatedFactory.isFactory());

        commas = (CommaSeparated)commaSeparatedFactory.adapt(map, Adapter.UNCHECKED);
        assertTrue(commaSeparatedFactory.isFactory());

        String listCs = commas.getCommaSeparated();
        assertEquals("comma separated map", "Foo:foo,Bar:bar", listCs);				
    }

    public void testUnCheckedFactoryAdapter() throws Exception {
        assertFalse(commaSeparatedFactory.isFactory());

        commas = (CommaSeparated)commaSeparatedFactory.adapt(list, Adapter.CHECKED);
        assertTrue(commaSeparatedFactory.isFactory());

        String listCs = commas.getCommaSeparated();
        assertEquals("comma separated list", "Foo,Bar", listCs);			
    }	

    public void testUnkownTypeUsingFactory() throws Exception {
        try {
            assertFalse(commaSeparatedFactory.isFactory());

            commas = (CommaSeparated)commaSeparatedFactory.adapt 
                    ("unknown type", Adapter.CHECKED);
        } catch (AdaptationException e) {
                    
        }
        assertFalse(commaSeparatedFactory.isFactory());

        assertNull("Factory does not handle strings", commas);
    }	*/


    public void testStaticFactoryAdapter() throws Exception {
        JAdapter<CommaSeparated,List> a =
            new JAdapter<CommaSeparated,List>();
        a.setAdapter(CommaSeparatedStaticFactory.class);
        a.setProvides(CommaSeparated.class);
        a.setFor(List.class);
        assertFalse(a.isFactory());

        CommaSeparated cs = a.adapt(list);
        assertTrue(a.isFactory());

        String s = cs.getCommaSeparated();
        assertEquals("comma separated list", "Foo,Bar", s);
    }


    @SuppressWarnings("unchecked")
    public void testNonGeneric() throws Exception {
        JAdapter adapter = new JAdapter();
        adapter.setProvides(CommaSeparated.class);
        adapter.setFor(List.class);
        adapter.setAdapter(CommaSeparatedList.class);
        assertFalse(adapter.isFactory());

        // we need to cast the result since we are not using generics here
        commas = (CommaSeparated)adapter.adapt(list);
        assertTrue(adapter.isFactory());

        String listCs = commas.getCommaSeparated();
        assertEquals("comma separated list", "Foo,Bar", listCs);        
    }	


    // reminder on how isAssignableFrom works
    // (just one of those "other left" things)
    public void testAssignable() throws Exception {
        boolean list = List.class.isAssignableFrom(LinkedList.class);
        boolean linked = LinkedList.class.isAssignableFrom(List.class);
        assertTrue(list);
        assertFalse(linked);
    }


    public void simpleUsage() throws Exception {
        List<String> list = new LinkedList<String>();
        list.add("foo");
        list.add("bar");

        CommaSeparatedList csl = new CommaSeparatedList();
        csl.setList(list);
        String s = csl.getCommaSeparated();
        assertEquals("foo,bar", s);

        CommaSeparatedFactory factory = new CommaSeparatedFactory();
        CommaSeparated csl1 = factory.getCommaSeparated(list);
        String s1 = csl1.getCommaSeparated();
        assertEquals("foo,bar", s1);

    }
    
    @SuppressWarnings("serial")
    public void testImplicitJAdapter() throws Exception {
        registry.register(CommaSeparated.class, CommaSeparatedMap.class, Map.class);
        CommaSeparated cs = registry.adapt(CommaSeparated.class, new HashMap<Object,Object>());
        assertNotNull("simple register api fails to ", cs);
        
        Map<String,String> anonMap = new HashMap<String,String>(){{put("anony", "map");}};
        cs = registry.adapt(CommaSeparated.class, anonMap);
        assertNotNull("instance with init code fails", cs);
    }
    
    public void testShouldFindAdapterMethodWithCorrectSignature(){
        JAdapter<CommaSeparated,List> a =
            new JAdapter<CommaSeparated,List>();
        a.setAdapter(CommaSeparatedFactoryMethod.class);
        a.setProvides(CommaSeparated.class);
        a.setFor(List.class);
        assertFalse(a.isFactory());

        CommaSeparated cs = a.adapt(list);
        assertTrue(a.isFactory());

        String s = cs.getCommaSeparated();
        assertEquals("comma separated list", "Foo,Bar", s);

        
    }
    
    public void testArbitrarySetter() throws Exception {
        registry.register(CommaSeparated.class, CommaSeparatedSetter.class, List.class);
        CommaSeparated cs = registry.adapt(CommaSeparated.class, list);
        assertEquals("Foo,Bar", cs.getCommaSeparated());
    }
    
    public void testAdapter() throws Exception {
        registry.register(CommaSeparated.class, CommaSeparatedAdapter.class, List.class);
        CommaSeparated cs = registry.adapt(CommaSeparated.class, list);
        assertEquals("Foo,Bar", cs.getCommaSeparated());        
    }
    
    public void testFunctionFactoryAdapter() throws Exception {
        Lambda<CommaSeparated,List> adapter = new Lambda<CommaSeparated,List>(){
            public CommaSeparated x(final List item) {
                return new CommaSeparatedList(){{setList(item);}};
            }
        };     
        
        registry.register(CommaSeparated.class, adapter, List.class);      
        CommaSeparated cs = registry.adapt(CommaSeparated.class, list);
        assertEquals("Foo,Bar", cs.getCommaSeparated());     
    }
    
    public void testMapList(){
        MapList adapter = new MapList();
        
        SortedMap map = adapter.adapt(list);
        assertTrue(map.containsKey(1));
        assertTrue(map.containsValue("Foo"));
    }
        
}
